package com.lifeverse.entity;

import com.lifeverse.entity.enums.ResourceStatus;
import com.lifeverse.entity.enums.ResourceType;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 资源实体类
 * 表示系统中的各种资源
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "resources", indexes = {
    @Index(name = "idx_resource_name", columnList = "name"),
    @Index(name = "idx_resource_type", columnList = "type"),
    @Index(name = "idx_resource_status", columnList = "status"),
    @Index(name = "idx_resource_owner", columnList = "owner_id"),
    @Index(name = "idx_resource_location", columnList = "location")
})
public class Resource extends BaseEntity {
    
    /**
     * 资源名称
     */
    @Column(name = "name", nullable = false, length = 100)
    private String name;
    
    /**
     * 资源类型
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "type", nullable = false, length = 20)
    private ResourceType type;
    
    /**
     * 资源状态
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false, length = 20)
    private ResourceStatus status = ResourceStatus.AVAILABLE;
    
    /**
     * 资源描述
     */
    @Column(name = "description", length = 500)
    private String description;
    
    /**
     * 资源拥有者
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner_id")
    private LifeEntity owner;
    
    /**
     * 当前使用者
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "current_user_id")
    private LifeEntity currentUser;
    
    /**
     * 资源容量/总量
     */
    @Column(name = "capacity", nullable = false, precision = 15, scale = 4)
    private BigDecimal capacity;
    
    /**
     * 已使用量
     */
    @Column(name = "used_amount", nullable = false, precision = 15, scale = 4)
    private BigDecimal usedAmount = BigDecimal.ZERO;
    
    /**
     * 可用量
     */
    @Column(name = "available_amount", nullable = false, precision = 15, scale = 4)
    private BigDecimal availableAmount;
    
    /**
     * 资源单位
     */
    @Column(name = "unit", length = 20)
    private String unit;
    
    /**
     * 资源成本（每单位）
     */
    @Column(name = "unit_cost", precision = 10, scale = 4)
    private BigDecimal unitCost;
    
    /**
     * 资源优先级（1-10）
     */
    @Column(name = "priority", nullable = false)
    private Integer priority = 5;
    
    /**
     * 资源位置
     */
    @Column(name = "location", length = 200)
    private String location;
    
    /**
     * 资源标签（JSON格式）
     */
    @Column(name = "tags", length = 500)
    private String tags;
    
    /**
     * 资源属性（JSON格式）
     */
    @Column(name = "attributes", columnDefinition = "TEXT")
    private String attributes;
    
    /**
     * 资源配置（JSON格式）
     */
    @Column(name = "configuration", columnDefinition = "TEXT")
    private String configuration;
    
    /**
     * 最小分配单位
     */
    @Column(name = "min_allocation_unit", precision = 15, scale = 4)
    private BigDecimal minAllocationUnit = BigDecimal.ONE;
    
    /**
     * 最大分配单位
     */
    @Column(name = "max_allocation_unit", precision = 15, scale = 4)
    private BigDecimal maxAllocationUnit;
    
    /**
     * 资源创建时间
     */
    @Column(name = "created_time", nullable = false)
    private LocalDateTime createdTime;
    
    /**
     * 最后使用时间
     */
    @Column(name = "last_used_at")
    private LocalDateTime lastUsedAt;
    
    /**
     * 最后维护时间
     */
    @Column(name = "last_maintenance_at")
    private LocalDateTime lastMaintenanceAt;
    
    /**
     * 下次维护时间
     */
    @Column(name = "next_maintenance_at")
    private LocalDateTime nextMaintenanceAt;
    
    /**
     * 资源过期时间
     */
    @Column(name = "expires_at")
    private LocalDateTime expiresAt;
    
    /**
     * 使用统计数据（JSON格式）
     */
    @Column(name = "usage_statistics", columnDefinition = "TEXT")
    private String usageStatistics;
    
    /**
     * 性能指标（JSON格式）
     */
    @Column(name = "performance_metrics", columnDefinition = "TEXT")
    private String performanceMetrics;
    
    /**
     * 资源分配记录
     */
    @OneToMany(mappedBy = "resource", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<ResourceAllocation> allocations = new ArrayList<>();
    
    @PrePersist
    protected void onCreate() {
        super.onCreate();
        if (createdTime == null) {
            createdTime = LocalDateTime.now();
        }
        if (availableAmount == null && capacity != null) {
            availableAmount = capacity.subtract(usedAmount);
        }
        if (maxAllocationUnit == null && capacity != null) {
            maxAllocationUnit = capacity;
        }
    }
    
    @PreUpdate
    protected void onUpdate() {
        super.onUpdate();
        if (capacity != null && usedAmount != null) {
            availableAmount = capacity.subtract(usedAmount);
        }
    }
    
    /**
     * 计算使用率
     */
    public BigDecimal getUsageRate() {
        if (capacity == null || capacity.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return usedAmount.divide(capacity, 4, java.math.RoundingMode.HALF_UP);
    }
    
    /**
     * 计算可用率
     */
    public BigDecimal getAvailabilityRate() {
        if (capacity == null || capacity.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return availableAmount.divide(capacity, 4, java.math.RoundingMode.HALF_UP);
    }
    
    /**
     * 判断是否可以分配指定数量
     */
    public boolean canAllocate(BigDecimal amount) {
        if (!status.isAvailable()) {
            return false;
        }
        
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        
        if (minAllocationUnit != null && amount.compareTo(minAllocationUnit) < 0) {
            return false;
        }
        
        if (maxAllocationUnit != null && amount.compareTo(maxAllocationUnit) > 0) {
            return false;
        }
        
        return availableAmount != null && availableAmount.compareTo(amount) >= 0;
    }
    
    /**
     * 分配资源
     */
    public boolean allocate(BigDecimal amount, LifeEntity user) {
        if (!canAllocate(amount)) {
            return false;
        }
        
        this.usedAmount = this.usedAmount.add(amount);
        this.availableAmount = this.availableAmount.subtract(amount);
        this.currentUser = user;
        this.lastUsedAt = LocalDateTime.now();
        
        if (this.availableAmount.compareTo(BigDecimal.ZERO) == 0) {
            this.status = ResourceStatus.EXHAUSTED;
        } else if (this.status == ResourceStatus.AVAILABLE) {
            this.status = ResourceStatus.IN_USE;
        }
        
        return true;
    }
    
    /**
     * 释放资源
     */
    public boolean release(BigDecimal amount) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        
        if (usedAmount.compareTo(amount) < 0) {
            return false;
        }
        
        this.usedAmount = this.usedAmount.subtract(amount);
        this.availableAmount = this.availableAmount.add(amount);
        
        if (this.usedAmount.compareTo(BigDecimal.ZERO) == 0) {
            this.currentUser = null;
            this.status = ResourceStatus.AVAILABLE;
        }
        
        return true;
    }
    
    /**
     * 判断是否需要维护
     */
    public boolean needsMaintenance() {
        if (nextMaintenanceAt == null) {
            return false;
        }
        return LocalDateTime.now().isAfter(nextMaintenanceAt);
    }
    
    /**
     * 判断是否已过期
     */
    public boolean isExpired() {
        if (expiresAt == null) {
            return false;
        }
        return LocalDateTime.now().isAfter(expiresAt);
    }
    
    /**
     * 更新使用时间
     */
    public void updateLastUsedTime() {
        this.lastUsedAt = LocalDateTime.now();
    }
    
    /**
     * 设置维护状态
     */
    public void setMaintenanceMode(boolean maintenance) {
        if (maintenance) {
            this.status = ResourceStatus.MAINTENANCE;
            this.lastMaintenanceAt = LocalDateTime.now();
        } else {
            this.status = ResourceStatus.AVAILABLE;
        }
    }
    
    /**
     * 计算总成本
     */
    public BigDecimal calculateTotalCost() {
        if (unitCost == null || usedAmount == null) {
            return BigDecimal.ZERO;
        }
        return unitCost.multiply(usedAmount);
    }
}